package cn.metona.utils;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.List;

public final class BigDecimalUtils {

    // 私有构造函数，防止实例化
    private BigDecimalUtils() {
        throw new UnsupportedOperationException("Utility class");
    }

    /**
     * 加法运算
     *
     * @param a 第一个数
     * @param b 第二个数
     * @return 两个数的和
     */
    public static BigDecimal add(BigDecimal a, BigDecimal b) {
        return a.add(b);
    }

    /**
     * 减法运算
     *
     * @param a 第一个数
     * @param b 第二个数
     * @return 两个数的差
     */
    public static BigDecimal subtract(BigDecimal a, BigDecimal b) {
        return a.subtract(b);
    }

    /**
     * 乘法运算
     *
     * @param a 第一个数
     * @param b 第二个数
     * @return 两个数的积
     */
    public static BigDecimal multiply(BigDecimal a, BigDecimal b) {
        return a.multiply(b);
    }

    /**
     * 除法运算
     *
     * @param a 第一个数
     * @param b 第二个数
     * @param scale 小数点后保留的位数
     * @param roundingMode 舍入模式
     * @return 两个数的商
     */
    public static BigDecimal divide(BigDecimal a, BigDecimal b, int scale, RoundingMode roundingMode) {
        return a.divide(b, scale, roundingMode);
    }

    /**
     * 比较两个 BigDecimal 的大小
     *
     * @param a 第一个数
     * @param b 第二个数
     * @return 如果 a > b 返回 1，a < b 返回 -1，a == b 返回 0
     */
    public static int compare(BigDecimal a, BigDecimal b) {
        return a.compareTo(b);
    }

    /**
     * 判断两个 BigDecimal 是否相等
     *
     * @param a 第一个数
     * @param b 第二个数
     * @return 如果相等返回 true，否则返回 false
     */
    public static boolean equals(BigDecimal a, BigDecimal b) {
        return a.compareTo(b) == 0;
    }

    /**
     * 四舍五入
     *
     * @param value 需要四舍五入的值
     * @param scale 小数点后保留的位数
     * @return 四舍五入后的值
     */
    public static BigDecimal round(BigDecimal value, int scale) {
        return value.setScale(scale, RoundingMode.HALF_UP);
    }

    /**
     * 判断一个 BigDecimal 是否为正数
     *
     * @param value 需要判断的值
     * @return 如果为正数返回 true，否则返回 false
     */
    public static boolean isPositive(BigDecimal value) {
        return value.compareTo(BigDecimal.ZERO) > 0;
    }

    /**
     * 判断一个 BigDecimal 是否为负数
     *
     * @param value 需要判断的值
     * @return 如果为负数返回 true，否则返回 false
     */
    public static boolean isNegative(BigDecimal value) {
        return value.compareTo(BigDecimal.ZERO) < 0;
    }

    /**
     * 判断一个 BigDecimal 是否为零
     *
     * @param value 需要判断的值
     * @return 如果为零返回 true，否则返回 false
     */
    public static boolean isZero(BigDecimal value) {
        return value.compareTo(BigDecimal.ZERO) == 0;
    }

    /**
     * 计算绝对值
     *
     * @param value 需要计算的值
     * @return 绝对值
     */
    public static BigDecimal abs(BigDecimal value) {
        return value.abs();
    }

    /**
     * 取反
     *
     * @param value 需要取反的值
     * @return 取反后的值
     */
    public static BigDecimal negate(BigDecimal value) {
        return value.negate();
    }

    /**
     * 计算幂运算
     *
     * @param base     基数
     * @param exponent 指数
     * @return 幂运算结果
     */
    public static BigDecimal pow(BigDecimal base, int exponent) {
        return base.pow(exponent);
    }

    /**
     * 计算多个 BigDecimal 的最大值
     *
     * @param values 多个 BigDecimal 值
     * @return 最大值
     */
    public static BigDecimal max(BigDecimal... values) {
        if (values == null || values.length == 0) {
            throw new IllegalArgumentException("Values array cannot be null or empty");
        }
        return Arrays.stream(values).max(BigDecimal::compareTo).orElseThrow();
    }

    /**
     * 计算多个 BigDecimal 的最小值
     *
     * @param values 多个 BigDecimal 值
     * @return 最小值
     */
    public static BigDecimal min(BigDecimal... values) {
        if (values == null || values.length == 0) {
            throw new IllegalArgumentException("Values array cannot be null or empty");
        }
        return Arrays.stream(values).min(BigDecimal::compareTo).orElseThrow();
    }

    /**
     * 格式化 BigDecimal 为字符串
     *
     * @param value  需要格式化的值
     * @param pattern 格式模式（如 "#,##0.00"）
     * @return 格式化后的字符串
     */
    public static String format(BigDecimal value, String pattern) {
        DecimalFormat decimalFormat = new DecimalFormat(pattern);
        return decimalFormat.format(value);
    }

    /**
     * 计算 BigDecimal 的平均值
     *
     * @param values 多个 BigDecimal 值
     * @param scale 小数点后保留的位数
     * @param roundingMode 舍入模式
     * @return 平均值
     */
    public static BigDecimal average(List<BigDecimal> values, int scale, RoundingMode roundingMode) {
        if (values == null || values.isEmpty()) {
            throw new IllegalArgumentException("Values list cannot be null or empty");
        }
        BigDecimal sum = values.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
        return sum.divide(new BigDecimal(values.size()), scale, roundingMode);
    }

    /**
     * 计算平方根
     *
     * @param value 需要计算的值
     * @param scale 小数点后保留的位数
     * @param roundingMode 舍入模式
     * @return 平方根
     */
    public static BigDecimal sqrt(BigDecimal value, int scale, RoundingMode roundingMode) {
        if (value.compareTo(BigDecimal.ZERO) < 0) {
            throw new ArithmeticException("Cannot compute square root of a negative number");
        }
        return value.sqrt(new MathContext(scale, roundingMode));
    }

    /**
     * 判断一个 BigDecimal 是否为整数
     *
     * @param value 需要判断的值
     * @return 如果是整数返回 true，否则返回 false
     */
    public static boolean isInteger(BigDecimal value) {
        return value.stripTrailingZeros().scale() <= 0;
    }

    /**
     * 转换为百分比
     *
     * @param value 需要转换的值
     * @param scale 小数点后保留的位数
     * @param roundingMode 舍入模式
     * @return 百分比值
     */
    public static BigDecimal toPercentage(BigDecimal value, int scale, RoundingMode roundingMode) {
        return value.multiply(new BigDecimal("100")).setScale(scale, roundingMode);
    }

    /**
     * 计算多个 BigDecimal 的总和
     *
     * @param values 多个 BigDecimal 值
     * @return 总和
     */
    public static BigDecimal sum(BigDecimal... values) {
        if (values == null || values.length == 0) {
            throw new IllegalArgumentException("Values array cannot be null or empty");
        }
        return Arrays.stream(values).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    /**
     * 检查一个 BigDecimal 是否在指定范围内
     *
     * @param value 需要检查的值
     * @param min   范围最小值
     * @param max   范围最大值
     * @return 如果在范围内返回 true，否则返回 false
     */
    public static boolean isInRange(BigDecimal value, BigDecimal min, BigDecimal max) {
        return value.compareTo(min) >= 0 && value.compareTo(max) <= 0;
    }
}
